package com.xakcop.p4reviewboard.actions;

import java.util.ArrayList;
import java.util.List;

import com.perforce.p4java.client.IClient;
import com.perforce.team.core.p4java.P4PendingChangelist;
import com.xakcop.p4reviewboard.Activator;
import com.xakcop.p4reviewboard.console.ProcessConsole;
import com.xakcop.p4reviewboard.prefs.PreferencePage;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.console.ConsolePlugin;

public class PostReviewAction implements IObjectActionDelegate {

  private static final String TITLE = "Post Review";

  private Shell shell;
  private P4PendingChangelist changelist;
  private Job postReviewJob;

  public PostReviewAction() {
    super();
  }

  public void setActivePart(IAction action, IWorkbenchPart targetPart) {
    shell = targetPart.getSite().getShell();
  }

  public void run(IAction action) {
    if (postReviewJob != null && postReviewJob.getState() != Job.NONE) {
      MessageDialog.openError(shell, TITLE, "Another post-review is running");
      return;
    }
    IPreferenceStore store = Activator.getDefault().getPreferenceStore();
    String postReviewExec = store.getString(PreferencePage.POST_REVIEW_EXECUTABLE);
    if ("".equals(postReviewExec)) {
      MessageDialog.openError(shell, TITLE, "No post-review executable specified.\n" +
          "Navigate to Window -> Preferences -> Review Board to specify executable.");
      return;
    }
    boolean addArgs = store.getBoolean(PreferencePage.PASS_ARGS_ON_LAUNCH);

    /*
     * Find p4client name associated with this pending changelist
     * and supply it as an argument. Create other arguments if necessary.
     */
    String postReviewArgs = createArgument("--p4-client=", changelist.getClientName());
    postReviewArgs += createArgument("--username=", store.getString(PreferencePage.POST_REVIEW_USERNAME));
    postReviewArgs += createArgument("--password=", store.getString(PreferencePage.POST_REVIEW_PASSWORD));
    postReviewArgs += createArgument("--server=", store.getString(PreferencePage.REVIEWBOARD_URL));
    postReviewArgs += createArgument("--repository-url=", store.getString(PreferencePage.REPOSITORY));
    postReviewArgs += " " + store.getString(PreferencePage.POST_REVIEW_ARGUMENTS);

    final List<String> command = createCommand(postReviewExec, postReviewArgs, addArgs);
    if (command == null) {
      return;
    }

    final String workingDir = getWorkingDir();
    Activator.trace("working dir: " + workingDir);

    final ProcessConsole console = ProcessConsole.getInstance();
    ConsolePlugin.getDefault().getConsoleManager().showConsoleView(console);
    postReviewJob = new Job("Execute post-review and display it's stdout/stderr on the console") {
      @Override
      protected IStatus run(IProgressMonitor monitor) {
        console.startProcess(command, workingDir);
        return Status.OK_STATUS;
      }
    };
    postReviewJob.setSystem(true);
    postReviewJob.schedule();
  }

  /**
   * Helper method to create argument: option/value pair.
   *
   * @param option option name
   * @param value the value for option
   * @return option/value or empty string
   */
  private String createArgument(String option, String value) {
    String arg = "";
    if (!"".equals(value)) {
      arg = " " + option + value.trim();
    }
    return arg;
  }

  List<String> createCommand(String executable, String args, boolean addArgs) {
    List<String> result = new ArrayList<String>();
    result.add(executable);
    int id = changelist.getId();
    args += " " + id;
    if (addArgs) {
      InputDialog inputDialog = new InputDialog(shell, TITLE, executable, args.trim(), null);
      if (inputDialog.open() == InputDialog.OK) {
        args = inputDialog.getValue();
      } else {
        return null;
      }
    }
    String[] argsArr = args.split("\\s+");
    for(String arg : argsArr) {
      if (!arg.equals("")) {
        result.add(arg);
      }
    }
    Activator.trace("cmd: " + result.toString());
    return result;
  }

  String getWorkingDir() {
    IClient client = changelist.getClient();
    return client.getRoot();
  }

  public void selectionChanged(IAction action, ISelection selection) {
    if (selection instanceof TreeSelection) {
      TreeSelection treeSelection = (TreeSelection) selection;
      Object firstElement = treeSelection.getFirstElement();
      if (firstElement instanceof P4PendingChangelist) {
        P4PendingChangelist changelist = (P4PendingChangelist) firstElement;
        this.changelist = changelist;
      }
    }
  }

}
